//Copyright (c) 2009, Sandeep Datta
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided 
//that the following conditions are met:
//
//* Redistributions of source code must retain the above copyright notice, this list of conditions and 
//the following disclaimer.
//
//* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//the following disclaimer in the documentation and/or other materials provided with the distribution.
//
//* Neither the name of Sandeep Datta nor the names of its contributors may be used to endorse or 
//promote products derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
//IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
//WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using System;
using System.Collections.Generic;
using System.Text;

namespace SharpInstall
{
    [Serializable]
    public class DataTypeInfo
    {
        ////////PUBLIC STUFF////////
        public DataType Type { get { return _type; } }
        public BaseDataType BaseType { get { return _baseType; } }
        public int MaxLength { get { return _maxLength; } }//0 implies variable length string
        
        public bool Localizable { 
            get { return _localizable; } 
            set { _localizable = value; } 
        }
        
        public bool Nullable { 
            get { return _nullable; } 
            set { _nullable = value; } 
        }
        
        public bool IsPrimary { 
            get { return _isPrimary; } 
            set { _isPrimary = value; } 
        }


        ////////CTORS////////
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="maxLen">Set this to zero to indicate strings of infinite length</param>
        /// <param name="localizable"></param>
        public DataTypeInfo(DataType type, int maxLen, bool localizable, bool isNullable, bool isPrimary)
        {
            _type = type;
            _baseType = GetBaseType(type);
            _maxLength = maxLen;
            _localizable = localizable;
            _nullable = isNullable;
            _isPrimary = isPrimary;
        }

        public DataTypeInfo(BaseDataType baseType, int maxLen, bool localizable, bool isNullable, bool isPrimary)
        {
            _type = DataType.None;
            _baseType = baseType;
            _maxLength = maxLen;
            _localizable = localizable;
            _nullable = isNullable;
            _isPrimary = isPrimary;
        }

        public string GetSqlType()
        {
            switch (BaseType)
            {
                case BaseDataType.Int16:
                    return sqlInt16;
                case BaseDataType.Int32:
                    return sqlInt32;
                case BaseDataType.String:
                    if (MaxLength == 0)
                        return sqlString;
                    return getFixedString(MaxLength);
                case BaseDataType.Binary:
                    return sqlBinaryStream;
                default:
                    throw new Exception("BUG: Unknown base type.");
            }
        }

        public string GetFullSqlType()
        {
            string notNull = Nullable ? "" : " NOT NULL";
            string localizable = Localizable ? " LOCALIZABLE" : "";
            switch (BaseType)
            {
                case BaseDataType.Int16:
                    return sqlInt16 + notNull;
                case BaseDataType.Int32:
                    return sqlInt32 + notNull;
                case BaseDataType.String:
                    if (MaxLength == 0)
                        return sqlString + notNull + localizable;
                    return getFixedString(MaxLength) + notNull + localizable;
                case BaseDataType.Binary:
                    return sqlBinaryStream + notNull;
                default:
                    throw new Exception("BUG: Unknown base type.");
            }
        }

        ////////PRIVATE STUFF////////

        private DataType _type;
        private BaseDataType _baseType;
        private int _maxLength;//0 implies variable length string
        private bool _localizable;
        private bool _nullable;
        private bool _isPrimary;

        private string sqlInt16 { get { return "SHORT"; } }//SHORT=INT=INTEGER=I2
        private string sqlInt32 { get { return "LONG"; } }//LONG=I4
        private string sqlString { get { return "LONGCHAR"; } }//=S0=CHAR(0)
        private string getFixedString(int maxLen) { return "CHAR(" + maxLen.ToString() + ")"; }//=S(n)=CHAR(n)
        private string sqlBinaryStream { get { return "OBJECT"; } }//=V0


        ////////STATIC STUFF////////

        static private DataTypeInfo _char255;
        static private DataTypeInfo _long;
        static private DataTypeInfo _short;
        static private DataTypeInfo _binary;

        static private Dictionary<DataType, BaseDataType> _baseTypeDict 
                                                            = new Dictionary<DataType, BaseDataType>();
        /// <summary>
        /// Static ctor
        /// </summary>
        static DataTypeInfo()
        {
            _char255 = new DataTypeInfo(BaseDataType.String, 255, false, false, false);
            _long = new DataTypeInfo(BaseDataType.Int32, 0, false, false, false);
            _short = new DataTypeInfo(BaseDataType.Int16, 0, false, false, false);
            _binary = new DataTypeInfo(BaseDataType.Binary, 0, false, false, false);
            populateSqlTypes();
        }

        private static void populateSqlTypes()
        {
            _baseTypeDict.Add(DataType.Text, BaseDataType.String);
            _baseTypeDict.Add(DataType.UpperCase, BaseDataType.String);
            _baseTypeDict.Add(DataType.LowerCase, BaseDataType.String);
            _baseTypeDict.Add(DataType.Integer, BaseDataType.Int16);
            _baseTypeDict.Add(DataType.DoubleInteger, BaseDataType.Int32);
            _baseTypeDict.Add(DataType.TimeOrDate, BaseDataType.Int16);
            _baseTypeDict.Add(DataType.Identifier, BaseDataType.String);
            _baseTypeDict.Add(DataType.Property, BaseDataType.String);
            _baseTypeDict.Add(DataType.Filename, BaseDataType.String);
            _baseTypeDict.Add(DataType.WildCardFilename, BaseDataType.String);
            _baseTypeDict.Add(DataType.Path, BaseDataType.String);
            _baseTypeDict.Add(DataType.Paths, BaseDataType.String);
            _baseTypeDict.Add(DataType.AnyPath, BaseDataType.String);
            _baseTypeDict.Add(DataType.DefaultDir, BaseDataType.String);
            _baseTypeDict.Add(DataType.RegPath, BaseDataType.String);
            _baseTypeDict.Add(DataType.Formatted, BaseDataType.String);
            _baseTypeDict.Add(DataType.Template, BaseDataType.String);
            _baseTypeDict.Add(DataType.Condition, BaseDataType.String);
            _baseTypeDict.Add(DataType.GUID, BaseDataType.String);
            _baseTypeDict.Add(DataType.Version, BaseDataType.String);
            _baseTypeDict.Add(DataType.Language, BaseDataType.String);
            _baseTypeDict.Add(DataType.Binary, BaseDataType.Binary);
            _baseTypeDict.Add(DataType.CustomSource, BaseDataType.String);
            _baseTypeDict.Add(DataType.Cabinet, BaseDataType.String);
            _baseTypeDict.Add(DataType.Shortcut, BaseDataType.String);
        }

        public static BaseDataType GetBaseType(DataType type)
        {
            return _baseTypeDict[type];
        }

        public static DataTypeInfo CHAR255 { get { return _char255; } }
        public static DataTypeInfo LONG { get { return _long; } }
        public static DataTypeInfo SHORT { get { return _short; } }
        public static DataTypeInfo BINARY { get { return _binary; } }
    }
}
